﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;
using NetTopologySuite.Algorithm;
using NetTopologySuite.Geometries;
using NetTopologySuite.IO;

namespace NetTopologySuite.Noding
{
	public class FastNodingValidator
	{
		public static IList<Coordinate> ComputeIntersections(IEnumerable<ISegmentString> segStrings)
		{
			FastNodingValidator fastNodingValidator = new FastNodingValidator(segStrings);
			fastNodingValidator.FindAllIntersections = true;
			bool isValid = fastNodingValidator.IsValid;
			return fastNodingValidator.Intersections;
		}

		public FastNodingValidator(IEnumerable<ISegmentString> segStrings)
		{
			this._segStrings.AddRange(segStrings);
		}

		public bool FindAllIntersections { get; set; }

		public IList<Coordinate> Intersections
		{
			get
			{
				return this._segInt.Intersections;
			}
		}

		public bool IsValid
		{
			get
			{
				this.Execute();
				return this._isValid;
			}
		}

		public string GetErrorMessage()
		{
			if (this.IsValid)
			{
				return "no intersections found";
			}
			Coordinate[] intersectionSegments = this._segInt.IntersectionSegments;
			return "found non-noded intersection between " + WKTWriter.ToLineString(intersectionSegments[0], intersectionSegments[1]) + " and " + WKTWriter.ToLineString(intersectionSegments[2], intersectionSegments[3]);
		}

		public void CheckValid()
		{
			if (!this.IsValid)
			{
				throw new TopologyException(this.GetErrorMessage(), this._segInt.InteriorIntersection);
			}
		}

		private void Execute()
		{
			if (this._segInt != null)
			{
				return;
			}
			this.CheckInteriorIntersections();
		}

		private void CheckInteriorIntersections()
		{
			this._isValid = true;
			this._segInt = new InteriorIntersectionFinder(this._li);
			this._segInt.FindAllIntersections = this.FindAllIntersections;
			new MCIndexNoder(this._segInt).ComputeNodes(this._segStrings);
			if (this._segInt.HasIntersection)
			{
				this._isValid = false;
				return;
			}
		}

		private readonly LineIntersector _li = new RobustLineIntersector();

		private readonly List<ISegmentString> _segStrings = new List<ISegmentString>();

		private InteriorIntersectionFinder _segInt;

		private bool _isValid = true;
	}
}
